#include "include.h"
#include "mt_timer.h"
#include <stdlib.h>

void timeout_handle(void *arg)
{
    int rc;
    struct timespec ts_start;

    //start time before call function
    rc = clock_gettime(CLOCK_MONOTONIC, &ts_start);


    // 10ms动一次，希望1s打印一次
    if(g_ulCurrentTime % 100 == 0)
    {
        //printf("     reports %ld.%09ld seconds\n", ts_start.tv_sec, ts_start.tv_nsec);
        //printf("[%s] %d\n", __func__, g_ulCurrentTime);
    }
    g_ulCurrentTime++;

}

TIMER_CREATE(test);

#define DELAY_TIMER_10MS 1000 * 1000 * 10
int vdTimer1_Delay10ms( void )
{
#if 0
    printf("[%s] Todo\n", __func__);
#else
    //printf("[%s] init timer\n", __func__);
    // int mt_timer_init()
    static int timer = -1;
    struct itimerspec itimespec;
    int repeat_cnt = -1;
    int max_timer_cnt = 5;
    // 最大数量为
    TIMER_INIT(test, max_timer_cnt);

    g_ulCurrentTime = 0;
    // 清空定时器
    //if(timer != -1)
    //{
    //    TIMER_DEL(test, timer);
    //}
    // it_value即是超时时间（相对时间），
    // 超时时间
    itimespec.it_value.tv_sec = 0;
    itimespec.it_value.tv_nsec = DELAY_TIMER_10MS;
    // 周期定时时间
    // 若想定义周期定时任务，则设置it_interval成员；
    // 若不想定义周期定时任务，则需设置it_interval成员都为0。
    itimespec.it_interval.tv_sec = 0;
    itimespec.it_interval.tv_nsec = DELAY_TIMER_10MS;

    timer = TIMER_ADD(test, &itimespec, repeat_cnt, timeout_handle, NULL, NULL);

    return 0;
#endif
}
void vdTimer1_deinit( void )
{
    TIMER_DEINIT(test);
}


void vdTimer3_ISR( void )
{
    g_ulCurrentTime++;
    //data_received[0] = 0x20;
    //data_received[1] = 0x02;
}

int BEEP_GPIO_INDEX = 19;

void vdInit_MCU_GPIO( void )
{
    int ret;
    BEEP_GPIO_INDEX = str_to_rk_gpio("RK_GPIO3_D4");
    printf("index %d\n", BEEP_GPIO_INDEX);
    ret = gpio_export(BEEP_GPIO_INDEX);
    //printf("[%s] ret = %d\n", __func__, ret);
    ret = gpio_direction_output(BEEP_GPIO_INDEX);
    //printf("[%s] ret = %d\n", __func__, ret);
}

void vdDeInit_MCU_GPIO( void )
{
    gpio_unexport(BEEP_GPIO_INDEX);
}

void vdReset_Chip( FlagStatus status )
{
    if ( !status )
    {
        //clr_P04;
        gpio_set_value(BEEP_GPIO_INDEX, 0);
        msleep(500);
    }
    else
    {
        gpio_set_value(BEEP_GPIO_INDEX, 1);
        msleep(500);
        //set_P04;
    }
}


bool bRxHdmi5vStatusDet( void )
{
#if 0
#else
    //if ( g_ucRxHdmi5vStatus == New_Rx_5V )
    if ( g_ucRxHdmi5vStatus == true )
    {
        return(FALSE);
    }
    //g_ucRxHdmi5vStatus = New_Rx_5V;
    g_ucRxHdmi5vStatus = true;
    if ( g_ucRxHdmi5vStatus ) //New_Rx_5V )
    {
        Delay_ms( 10 );
        if ( g_ucRxHdmi5vStatus )// New_Rx_5V )
        {
            g_bFlagSystemStart = TRUE;
            printf( " RX 5V HIGH!\n");
            //vdSet_RX_HPD( High );
        }
        return(TRUE);
    }
    else
    {
        printf( " ========= RX 5V LOW!========= \n\n");
        vdSet_RX_HPD( Low );
        g_Flag_Init_Finished = FALSE;
    }
    return(TRUE);
#endif
}


bool bTxHpdDetect()
{
    u8  i = 0, loopx = 0, loopy = 0;
    u8  newtxhpdstatus[2] = { 0, 0 };
    u8  newhpd = 0, oldhpd = 0;

    newtxhpdstatus[0]   = HDMI_ReadI2C_Byte( 0xf5 ) & 0x0F;//use chip to detect  the hpd,we can read the register 0xf5.
    newtxhpdstatus[0] = true;//newtxhpdstatus[0];
    if ( (newtxhpdstatus[0] == uOldTxPlugStatus[0]) )
    {
        return(FALSE);//tx hpd not changed
    }
    for ( loopy = 0; loopy < 4; loopy++ )
    {
        newhpd  = newtxhpdstatus[0] & (1 << loopy);
        oldhpd  = uOldTxPlugStatus[0] & (1 << loopy);
        if ( newhpd != oldhpd )
        {
            if ( (oldhpd == 0) && (newhpd != 0) )
            {
                g_ucTxPlugNumber++;
                if ( g_ucTxPlugNumber == 1 )
                {
                    FlagStartWork = TRUE;
                }
            }
            else
            {
                g_ucTxPlugNumber--;
            }
        }
    }
    if ( g_ucTxPlugNumber == 0 )
    {
        printf("[%s] g_ucTxPlugNumber == 0\n", __func__);
        FlagStartWork = FALSE;
        vdSet_RX_HPD( Low );
        g_Flag_Init_Finished = FALSE;
    }
    else
    {
        printf( "TX_Changed\n");
    }
    uOldTxPlugStatus[0] = newtxhpdstatus[0];
    return(TRUE);
}


int vdMcu_SystemReset( void )
{
    if ( g_ulCurrentTime > 0xffffff00 )
    {
        g_ulCurrentTime = 0;
        return 1;
    }
    return 0;
}


int vdChip_Init(void)
{
    static unsigned char    s_InitialStage  = 0;
    static unsigned long    s_ulLastTime    = 0;
    static unsigned short   s_usDelayTime   = 0;
    if ( s_ulLastTime + s_usDelayTime > g_ulCurrentTime )
    {
        return 0;
    }
    s_ulLastTime = g_ulCurrentTime;

    //printf("[%s] s_InitialStage %d/2\n", __func__, s_InitialStage);
    switch ( s_InitialStage )
    {
    case 0:
        vdReset_Chip( RESET );
        printf( "CHIP RESET\n");
        s_InitialStage++;
        s_usDelayTime = MS_100;
        break;
    case 1:
        vdReset_Chip( SET );
        printf( "CHIP RESET DONE\n");
        s_InitialStage++;
        s_usDelayTime = MS_100;
        break;
    case 2:
        vdSet_RX_HPD( Low );//set rx hpd low
        vdInitLT86102UX();//init LT86102UX
        vdTx_Drive_Config( OFF );//close tx
        printf( "=========== LT86102UX RESET DONE ===========\n");
        s_InitialStage      = 0;
        s_usDelayTime       = MS_100;
        data_received[0]=0;
        data_received[1]=0;
        data_num=0;
        g_Flag_Init_Finished    = TRUE;
        uOldTxPlugStatus[0]     = 0; // force
        g_ucTxPlugNumber        = 0;
        g_Startstage_clr[0]     =TRUE;
        g_Startstage_clr[1]     =TRUE;
        g_Startstage_clr[2]     =TRUE;
        g_bFlagHdmi20True       = FALSE;
        g_ucRxHdmi5vStatus      = FALSE;
    default:
        s_InitialStage = 0;
        return 1;
    }
    return 0;
}


int vStart_work(void)
{
    static unsigned char    s_StartStage        = 0;
    static unsigned long    s_ulLastStartTime   = 0;
    static unsigned short   s_usDelayTime       = 0;
    //if ( s_ulLastStartTime + s_usDelayTime > g_ulCurrentTime )
    //{
    //    return 0;
    //}
    s_ulLastStartTime = g_ulCurrentTime;
    if(g_Startstage_clr[0])
    {
        s_StartStage=0;
        g_Startstage_clr[0]=FALSE;
    }
    //printf("[%s]s_StartStage %d/2\n", __func__, s_StartStage);
    switch ( s_StartStage )
    {
    case 0:
        bTxHpdDetect();//used to detect the hpd
        bRxHdmi5vStatusDet();//used to detect the rx 5v
        if ( FlagStartWork && g_ucRxHdmi5vStatus )
        {
            FlagStartWork       = FALSE;
            g_Systerm_start[0]  = TRUE;
            s_StartStage++;
            s_usDelayTime = MS_500;
        }
        else
        {
            s_StartStage    = 0;
            s_usDelayTime   = MS_100;//per 300ms detect the hpd and rx change once.
        }
        break;
    case 1:
        vdSet_RX_HPD( High );//set rx hpd high
        s_StartStage++;
        s_usDelayTime = 0;
        break;
    case 2:
        s_StartStage            = 0;
        s_usDelayTime           = MS_100;
        return 1;
    default:
        s_StartStage    = 0;
        s_usDelayTime= 0;
        break;
    }
    return 0;
}


int vdClk_Stable_Config(void)
{
    static unsigned char    s_StartStage        = 0;
    static unsigned long    s_ulLastStartTime   = 0;
    static unsigned short   s_usDelayTime       = 0;
    static u8 i=0;

    if ( s_ulLastStartTime + s_usDelayTime > g_ulCurrentTime )
    {
        //printf("[%s]return s_ulLastStartTime + s_usDelayTime > g_ulCurrentTime\n", __func__);
        return 0;
    }
    s_ulLastStartTime = g_ulCurrentTime;
    if(Flag_ClkStable==FALSE)
    {
        //printf("[%s]return Flag_ClkStable\n", __func__);
        s_StartStage=0;
        return 0;
    }
    if(g_Startstage_clr[1])
    {
        //printf("[%s]g_Startstage_clr[1]\n", __func__);
        s_StartStage=0;
        g_Startstage_clr[1]=FALSE;
    }
    //printf("[%s]s_StartStage %d/4\n", __func__, s_StartStage);
    switch ( s_StartStage )
    {
    case 0:
        //printf( "Config LT86101UXE\n");
        vdTx_Drive_Config( ON );
        vdHdmiVerStatusDet();//detect the hdmi version is hdmi 2.0 or hdmi 1.4
        s_StartStage++;
        s_usDelayTime = 0;
        break;
    case 1:
        //vdTxTermCalibration();
        if ( g_bFlagHdmi20True )
        {
            //printf("sofeware HDMI2.0 select\n");
            HDMI_WriteI2C_Byte( 0x8e, 0x66 );
            HDMI_WriteI2C_Byte( 0x97, 0x66 );
            HDMI_WriteI2C_Byte( 0xE1, 0xf0 );       /*sofeware HDMI2.0 select//// */
        }
        else
        {
            printf("sofeware HDMI1.4 select\n");
            HDMI_WriteI2C_Byte( 0x8e, 0x64 );
            HDMI_WriteI2C_Byte( 0x97, 0x64 );
            HDMI_WriteI2C_Byte( 0xE1, 0xb0 );       /*sofeware HDMI1.4 select//// */
        }
        s_StartStage++;
        s_usDelayTime = 0;
        break;

    case 2:
#if 1
        if(bTmdsClkChangeDet())
        {
            printf("Break\n");
            printf("clk change detected\n");
            break;
        }
        else{
            printf("clk not change\n");
        }
#else
        printf("Skip clk change det\n");
#endif
        vdRxPllStepSet();
        vdRxPllCalibration( LT86101UXE, 0 );
        vdTxPllCalibration();
        Chip_Resolution_Det();
        //HDMI_WriteI2C_Byte( 0xd5, 0x28 );                  /*set eq register */
        //HDMI_WriteI2C_Byte( 0xd6, 0x28);                  /*set eq register */
        //HDMI_WriteI2C_Byte( 0xd7, 0x28 );                  /*set eq register */
        //vdTxPllCalibration();
        s_StartStage++;
        s_usDelayTime       = 0;
        break;
    case 3:
        if ( HDMI_ReadI2C_Byte( 0x5c ) & 0x01 )
        {
            //printf("g_bFlagRxPllLock[0] = TRUE\n");
            g_bFlagRxPllLock[0] = TRUE;
            HDMI_WriteI2C_Byte( 0x8a, 0x08 );
        }
        else
        {
            printf("LT86101UXE PLL UNLOCK LOCK\n");
            g_bFlagRxPllLock[0] = FALSE;
        }
        if ( g_bFlagRxPllLock[0] )
        {
            vdTxStatusSet();
            HDMI_WriteI2C_Byte( 0x19, 0x03 );
            HDMI_WriteI2C_Byte( 0x19, 0x00 );
            printf( " LT86101UXE PLL LOCK\n");
            s_StartStage        = 4;
            s_usDelayTime       = MS;
            g_bFlagRxPllLock[0] = FALSE;
            //while(1);
        }
        else
        {
            i++;
            if(i<20)
            {

                s_StartStage    = 3;
                s_usDelayTime   = MS_20;
            }
            else
            {
                i=0;
                s_StartStage    = 4;
                s_usDelayTime   = MS;
            }
        }
        break;
    case 4:
        //vdTxScdcWriteHandle( TX_ALL );
        s_StartStage        = 4;
        s_usDelayTime       = MS_20;
        return 1;
    default:
        s_StartStage    = 0;
        s_usDelayTime   = 0;
        break;
    }
    return 0;
}

int CLK_det(void)
{
    if ( bTmdsClkStableDet( LT86101UXE )&&g_ucRxHdmi5vStatus )//used to detect the clk is stable or not,Cycle detection
    {
        if ( bHdmiVerChangeDet() || bTmdsClkChangeDet() )
        {
            printf( " CLK stable\n");
            g_Startstage_clr[1]=TRUE;
        }
        Flag_ClkStable=TRUE;
        return 1;
    }
    else
    {
        vdTx_Drive_Config( OFF );
        Flag_ClkStable=FALSE;
    }
    return 0;
}

void Error_Counter( void )
{
    u16 uieq_errcnt_d0  = 0x0000;
    u16 uieq_errcnt_d1  = 0x0000;
    u16 uieq_errcnt_d2  = 0x0000;

    uieq_errcnt_d0  = HDMI_ReadI2C_Byte( 0x67 );
    uieq_errcnt_d0  = uieq_errcnt_d0 << 8;
    uieq_errcnt_d0  = uieq_errcnt_d0 + HDMI_ReadI2C_Byte( 0x66 );   /*read D0 error count */

    uieq_errcnt_d1  = HDMI_ReadI2C_Byte( 0x69 );
    uieq_errcnt_d1  = uieq_errcnt_d1 << 8;
    uieq_errcnt_d1  = uieq_errcnt_d1 + HDMI_ReadI2C_Byte( 0x68 );   /*read D1 error count */

    uieq_errcnt_d2  = HDMI_ReadI2C_Byte( 0x6B );
    uieq_errcnt_d2  = uieq_errcnt_d2 << 8;
    uieq_errcnt_d2  = uieq_errcnt_d2 + HDMI_ReadI2C_Byte( 0x6A );   /*read D2 error count */
    HDMI_WriteI2C_Byte( 0x03, 0xdf );
    Delay_ms( 10 );
    HDMI_WriteI2C_Byte( 0x03, 0xff );//reset error counter
    printf( "D0:ERROR_COUNT =%x \n",(u16)uieq_errcnt_d0 );
    printf( "D1:ERROR_COUNT =%x \n",(u16) uieq_errcnt_d1 );
    printf( "D2:ERROR_COUNT =%x \n",(u16)uieq_errcnt_d2 );
}


void vdPrintError( void )
{
    static unsigned long    s_ulLastStartTime   = 0;
    static unsigned short   s_usDelayTime       = TWO_SECOND;//Perform every two seconds.
    //if ( s_ulLastStartTime + s_usDelayTime > g_ulCurrentTime )
    //{
    //    return;
    //}
    //printf("[%s] ***********************\n", __func__);
    s_ulLastStartTime = g_ulCurrentTime;
    if ( g_bFlagHdmi20True )
    {
        printf( "CHIP A\n");
        Error_Counter();
    }
    if((HDMI_ReadI2C_Byte( 0x54 ) & 0x03)==0x03)
    {
        //g_Systerm_start[0]    = TRUE;
        HDMI_WriteI2C_Byte( 0x19, 0x03 );
        HDMI_WriteI2C_Byte( 0x19, 0x00 );
        printf( "***CLK INT***\n"); // 时钟产生中断
    }
}


void Init_I2C(int i2c_bus)
{
    init_i2c(i2c_bus);
}
void I2C_ISR(void)
{
#if 0
    switch (I2STAT)
    {
    case 0x00:
        //printf( "0x00\n");
        STO = 1;
        break;
    case 0x60:
        //printf( "0x60\n");
        AA = 1;
        //P3 = 0x60;
        break;
    case 0x68:
        //printf( "0x68\n");
        P02 = 0;
        while(1);
        break;
    case 0x80:
        //printf( "0x80\n");
        //P3 = 0x80;
        received = I2DAT;
        if (data_num==0&&received == 0x20)
        {
            data_received[0] = 0x20;
            //printf( "data0=%x",(u16)data_received[0]  );
            data_num++;
            AA = 1;
        }
        else if(data_num==1&&data_received[0] == 0x20)
        {
            data_received[1]=received;
            //printf( "data1=%x",(u16)data_received[1]  );
            data_num=0;
            AA = 0;
        }
        break;
    case 0x88:
        //printf( "0x88\n");
        //P3 = 0x88;
        // data_received[data_num] = I2DAT;
        //printf( "num=%x",(u16)data_num );
        //printf( "data3=%x",(u16)data_received[data_num] );
        data_num = 0;
        AA = 1;
        break;
    case 0xA0:
        //printf( "0xa0\n");
        //P3 = 0xA0;
        AA = 1;
        break;
    case 0xA8:
        //printf( "0xa8\n");
        //P3 = 0xA0;
        //data_num=0;
        //data_received[0]=0;
        //data_received[1]=0;
        I2DAT = 0xff;//data_received[data_num];
        //data_num++;
        AA = 1;
        break;
    case 0xB8:
        //printf( "0xb8\n");
        //P3 = 0xB8;
        I2DAT = 0xff;//data_received[data_num];
        //data_num++;
        AA = 1;
        break;
    case 0xC0:
        //printf( "0xc0\n");
        received = I2DAT;
        if (data_num==0&&received == 0x20)
        {
            data_received[0] = 0x20;
            //printf( "data0=%x",(u16)data_received[0]  );
            data_num++;
            AA = 1;
        }
        else if(data_num==1&&data_received[0] == 0x20)
        {
        if(received==0xff)
        {
            received=0x00;
        }
            data_received[1]=received;
            //printf( "data1=%x",(u16)data_received[1]  );
            data_num=0;
            AA = 0;
        }
        //data_received[0]=0;
        data_num=0;
        AA = 1;
        break;
    case 0xC8:
        //printf( "0xc8\n");
        //P3 = 0xC8;
        AA = 1;
        break;
    }
    SI = 0;
    while(STO);
#else
    data_received[0] = 0x20;
    data_received[1] = 0x02;
#endif
}
